using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace PerCiGal.WinForm.Controls
{
    public class PCGListView : ListView
    {
        private int _startGroupIndex;

        // Determine whether Windows XP or a later
        // operating system is present.
        private readonly bool _isRunningXpOrLater = OSFeature.Feature.IsPresent(OSFeature.Themes);

        // Declare a Hashtable array in which to store the groups.
        private Hashtable[] _groupTables;

        // Declare a variable to store the current grouping column.
        int _groupColumn;

        public PCGListView()
        {
            ColumnClick += PCGListViewColumnClick;
        }

        public int SetStarterGroup
        {
            set
            {
                _startGroupIndex = value;
            }
            get
            {
                return _startGroupIndex;
            }

        }

        private static bool PresentArgs(IEnumerable<string> args, string colName)
        {
            if (args != null)
            {
                return args.Any(arg => arg == colName);
            }

            return false;
        }

        public void OttimizzaListView(string[] args, int offset)
        {
            foreach (ColumnHeader col in Columns)
            {
                if (col.Index == 0)
                {
                    col.Width = 0;
                }
                else if (PresentArgs(args, col.Text))
                {
                    col.Width = 0;
                }
                else
                {
                    col.Width = col.Text.Length * ((int)Font.Size + offset);

                    for (int c = 0; c < Items.Count; c++)
                    {
                        try
                        {
                            int actualWidth = Items[c].SubItems[col.Index].Text.Length * ((int)Font.Size + offset);

                            if (actualWidth > col.Width)
                            {
                                col.Width = actualWidth;
                            }
                        }
                        catch
                        { }
                    }
                }
            }

            if (Items.Count > 0)
            {
                Items[Items.Count - 1].Selected = true;
            }
        }

        public void OttimizzaListViewWithImage(string[] args, int offset)
        {
            foreach (ColumnHeader col in Columns)
            {
                if (col.Index == 0)
                {
                    continue;
                }
                if (PresentArgs(args, col.Text))
                {
                    col.Width = 0;
                }
                else
                {
                    col.Width = col.Text.Length * ((int)Font.Size + offset);

                    for (int c = 0; c < Items.Count; c++)
                    {
                        try
                        {
                            int actualWidth = Items[c].SubItems[col.Index].Text.Length * ((int)Font.Size + offset);

                            if (actualWidth > col.Width)
                            {
                                col.Width = actualWidth;
                            }
                        }
                        catch
                        { }
                    }
                }
            }

            if (Items.Count > 0)
            {
                Items[Items.Count - 1].Selected = true;
            }
        }

        public void ImpostaGroup()
        {
            if (_isRunningXpOrLater)
            {
                // Create the groupsTable array and populate it with one 
                // hash table for each column.
                _groupTables = new Hashtable[Columns.Count];
                for (int column = 0; column < Columns.Count; column++)
                {
                    // Create a hash table containing all the groups 
                    // needed for a single column.
                    _groupTables[column] = CreateGroupsTable(column);
                }

                // Start with the groups created for the Title column.
                SetGroups(_startGroupIndex);
            }
        }

        void PCGListViewColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Set the sort order to ascending when changing
            // column groups; otherwise, reverse the sort order.
            if (Sorting == SortOrder.Descending ||
                (_isRunningXpOrLater && (e.Column != _groupColumn)))
            {
                Sorting = SortOrder.Ascending;
            }
            else
            {
                Sorting = SortOrder.Descending;
            }
            _groupColumn = e.Column;

            // Set the groups to those created for the clicked column.
            if (_isRunningXpOrLater)
            {
                try
                {
                    SetGroups(e.Column);
                }
                catch { }
            }
        }

        // Sets myListView to the groups created for the specified column.
        private void SetGroups(int column)
        {
            // Remove the current groups.
            Groups.Clear();

            // Retrieve the hash table corresponding to the column.
            var groups = _groupTables[column];

            // Copy the groups for the column to an array.
            var groupsArray = new ListViewGroup[groups.Count];
            groups.Values.CopyTo(groupsArray, 0);

            // Sort the groups and add them to myListView.
            Array.Sort(groupsArray, new ListViewGroupSorter(Sorting));
            Groups.AddRange(groupsArray);

            // Iterate through the items in myListView, assigning each 
            // one to the appropriate group.
            foreach (ListViewItem item in Items)
            {
                // Retrieve the subitem text corresponding to the column.
                string subItemText = item.SubItems[column].Text;

                // For the Title column, use only the first letter.
                if ((column == 0) & (subItemText != string.Empty))
                {
                    subItemText = subItemText.Substring(0, 1);
                }

                // Assign the item to the matching group.
                item.Group = (ListViewGroup)groups[subItemText];
            }
        }

        // Creates a Hashtable object with one entry for each unique
        // subitem value (or initial letter for the parent item)
        // in the specified column.
        private Hashtable CreateGroupsTable(int column)
        {
            // Create a Hashtable object.
            var groups = new Hashtable();

            // Iterate through the items in myListView.
            foreach (ListViewItem item in Items)
            {
                // Retrieve the text value for the column.
                string subItemText = item.SubItems[column].Text;

                // Use the initial letter instead if it is the first column.
                if ( (column == 0) & (subItemText != string.Empty))
                {
                    subItemText = subItemText.Substring(0, 1);
                }

                // If the groups table does not already contain a group
                // for the subItemText value, add a new group using the 
                // subItemText value for the group header and Hashtable key.
                if (!groups.Contains(subItemText))
                {
                    groups.Add(subItemText, new ListViewGroup(subItemText,
                        HorizontalAlignment.Left));
                }
            }

            // Return the Hashtable object.
            return groups;
        }

        // Sorts ListViewGroup objects by header value.
        private class ListViewGroupSorter : IComparer
        {
            private readonly SortOrder _order;

            // Stores the sort order.
            public ListViewGroupSorter(SortOrder theOrder)
            {
                _order = theOrder;
            }

            // Compares the groups by header value, using the saved sort
            // order to return the correct value.
            public int Compare(object x, object y)
            {
                int result = String.Compare(
                    ((ListViewGroup)x).Header,
                    ((ListViewGroup)y).Header
                );
                if (_order == SortOrder.Ascending)
                {
                    return result;
                }
                return -result;
            }
        }
    }
}
